import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateCommentDto, QueryCommentListDto } from '@/modules/comment/dto/dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Comment } from '@/modules/comment/entities/comment.entity';
import { Repository } from 'typeorm';
import { Article } from '@/modules/article/entities/article.entity';

@Injectable()
export class CommentService {
  constructor(
    @InjectRepository(Comment)
    private readonly commentRepository: Repository<Comment>,
    @InjectRepository(Article)
    private readonly articleRepository: Repository<Article>,
  ) {}

  /**
   * 创建评论
   * @param data
   * @param userId
   */
  async createComment(data: CreateCommentDto, userId: number) {
    // 查询文章是否存在
    const article = await this.articleRepository.findOne({
      where: { article_id: data.articleId },
    });
    if (!article) {
      throw new HttpException('文章不存在', HttpStatus.BAD_REQUEST);
    }

    // 查询评论父节点是否存在并获取父评论的用户id
    let replyUserId = null;
    if (data.parentId) {
      const parentComment = await this.commentRepository.findOne({
        where: { commentId: data.parentId },
        relations: ['user'],
      });
      if (!parentComment) {
        throw new HttpException('父评论不存在', HttpStatus.BAD_REQUEST);
      }
      // 获取父评论的用户id
      replyUserId = parentComment.user.id;
    }

    // 保存评论
    const comment = await this.commentRepository.save({
      content: data.content,
      article: { article_id: data.articleId },
      parent: data.parentId ? { commentId: data.parentId } : null,
      user: { id: userId },
      replyUser: replyUserId ? { id: replyUserId } : null,
    });

    // 添加文章表中评论数量统计
    await this.articleRepository.increment(
      { article_id: data.articleId },
      'article_comment_count',
      1,
    );

    return this.commentRepository.findOne({
      where: { commentId: comment.commentId },
    });
  }

  /**
   * 查询根节点评论列表
   * @param id
   * @param query
   */
  async queryCommentList(id: number, query: QueryCommentListDto) {
    const treeRepository = this.commentRepository.manager.getTreeRepository(Comment);

    const queryBuilder = this.commentRepository.createQueryBuilder('comment');

    // 查询文章下的评论
    queryBuilder.where('comment.articleId = :articleId', { articleId: id });
    // 查询根节点，即parent为null的节点
    queryBuilder.andWhere('comment.parentCommentId IS NULL');

    // 添加分页
    queryBuilder.skip((query.pageNo - 1) * query.pageSize);
    queryBuilder.take(query.pageSize);

    // 添加排序
    queryBuilder.orderBy('comment.updateDate', query.sort);

    // 关联用户表
    queryBuilder.leftJoinAndSelect('comment.user', 'user');

    // 执行查询
    const [list, total] = await queryBuilder.getManyAndCount();

    const childrenCountList: number[] = [];
    // 查询子节点，只查询两个最新的评论用于展示
    for (const item of list) {
      const descendantsQueryBuilder = treeRepository.createDescendantsQueryBuilder(
        'childrenComment',
        'closureTable',
        item,
      );

      // 不查询根节点
      descendantsQueryBuilder.andWhere('childrenComment.commentId != :parentCommentId', {
        parentCommentId: item.commentId,
      });
      descendantsQueryBuilder.orderBy('childrenComment.updateDate', 'DESC');
      descendantsQueryBuilder.take(2);

      // 关联用户表
      descendantsQueryBuilder.leftJoinAndSelect('childrenComment.user', 'user');
      // 关联回复用户表
      descendantsQueryBuilder.leftJoinAndSelect('childrenComment.replyUser', 'replyUser');
      const [commentList, count] = await descendantsQueryBuilder.getManyAndCount();
      childrenCountList.push(count);
      item.children = commentList;
    }

    // 插入子评论的数量
    const withCountList = list.map((item, index) => {
      return { ...item, childrenCount: childrenCountList[index] };
    });
    return {
      list: withCountList,
      total,
      pageNo: query.pageNo,
      pageSize: query.pageSize,
    };
  }

  /**
   * 按父节点id查询对应的子节点评论列表
   * @param id
   * @param query
   */
  async queryChildrenCommentList(id: number, query: QueryCommentListDto) {
    const treeRepository = this.commentRepository.manager.getTreeRepository(Comment);

    // 查询父节点
    const parentComment = await this.commentRepository.findOne({
      where: { commentId: id },
    });

    if (!parentComment) {
      throw new HttpException('父评论不存在', HttpStatus.BAD_REQUEST);
    }

    // 查询子节点
    const descendantsQueryBuilder = treeRepository.createDescendantsQueryBuilder(
      'childrenComment',
      'closureTable',
      parentComment,
    );
    // 不查询根节点
    descendantsQueryBuilder.andWhere('childrenComment.commentId != :parentCommentId', {
      parentCommentId: parentComment.commentId,
    });

    // 添加分页
    descendantsQueryBuilder.skip((query.pageNo - 1) * query.pageSize);
    descendantsQueryBuilder.take(query.pageSize);

    // 添加排序
    descendantsQueryBuilder.orderBy('childrenComment.updateDate', query.sort);

    // 关联用户表
    descendantsQueryBuilder.leftJoinAndSelect('childrenComment.user', 'user');
    // 关联回复用户表
    descendantsQueryBuilder.leftJoinAndSelect('childrenComment.replyUser', 'replyUser');

    // 执行查询
    const [list, total] = await descendantsQueryBuilder.getManyAndCount();

    return {
      list,
      total,
      pageNo: query.pageNo,
      pageSize: query.pageSize,
    };
  }

  async queryFlatCommentList(query: QueryCommentListDto) {
    return await this.commentRepository.find({
      skip: (query.pageNo - 1) * query.pageSize,
      take: query.pageSize,
      order: { updateDate: query.sort },
    });
  }

  async deleteComment(id: number) {
    const comment = await this.commentRepository.findOne({
      where: { commentId: id },
    });

    if (!comment) {
      throw new HttpException('评论不存在', HttpStatus.BAD_REQUEST);
    }

    await this.commentRepository.softDelete(id);
  }
}
